import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Created by 1 on 2021/12/4.
 */
public class LRUCacheManager<T> extends LinkedHashMap<String,LRUEntity<T>>{

    private int maxSize;
    private int lockSize;

    private Map<Integer,EasyKeyLock> lockMap;


    public LRUCacheManager(int initialCapacity,int maxSize,int lockSize) {
        super(initialCapacity);
        this.maxSize = maxSize;
        this.lockSize = lockSize;
        this.lockSize = lockSize;
        lockMap = new HashMap<>();
        for (int i = 0;i < lockSize;i++) {
            lockMap.put(i, new EasyKeyLock());
        }

    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<String, LRUEntity<T>> eldest) {
        if (size() > this.maxSize) {
            return true;
        }
        return false;
    }


    public T getCache(String key) {
        LRUEntity e = super.get(key);

        if (e != null) {
            if (e.getExpireTime() != null && e.getExpireTime().before(new Date())) {
                synchronized (e) {
                    if (get(key) != null) {
                        this.remove(key);
                    }
                }
                return null;
            }
            return (T) e.getObj();
        } else {
            return null;
        }
    }

    public void putCache(String key, T obj, Long ttl) {
        LRUEntity<T> e = new LRUEntity();
        e.setObj(obj);
        if (ttl != null) {
            Date d = new Date();
            d.setTime(d.getTime() + ttl);
            e.setExpireTime(d);
        }
        super.put(key,e);
    }

    public void lockInterruptiblyByKey(String key) throws InterruptedException {
        EasyKeyLock rLock = lockMap.get(Math.abs(key.hashCode() % this.lockSize));
        rLock.lockInterruptibly();
    }

    public void unlockAllByKey(String key) {
        EasyKeyLock rLock = lockMap.get(Math.abs(key.hashCode() % this.lockSize));
        rLock.unlockAll();
    }

    public void unlockByKey(String key) {
        EasyKeyLock rLock = lockMap.get(Math.abs(key.hashCode() % this.lockSize));
        rLock.unlock();
    }
}
